//-------------------------------------------------------------------------------------
// <copyright file="ExportBindings.cs" company="Achmea">
// Copyright (c) Microsoft Corporation.  All rights reserved.
// THIS CODE AND INFORMATION ARE PROVIDED "AS IS" WITHOUT WARRANTY OF ANY 
// KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
// PARTICULAR PURPOSE.
// </copyright>
// <summary>
//      Exports the bindings of an assembly in BizTalk to an XML file.
// </summary>  
//-------------------------------------------------------------------------------------
namespace Microsoft.Sdc.Tasks.BizTalk2006.Application
{
    using System;
    using System.Data.SqlClient;
    using System.Globalization;
    using System.IO;
    using System.Reflection;
    using System.Text;
    using Microsoft.BizTalk.Deployment.Binding;
    using Microsoft.BizTalk.ExplorerOM;

    /// <summary>
    /// Exports the bindings of an BizTalk application to an XML file.
    /// </summary>
    /// <remarks>
    /// <code>
    /// <![CDATA[<BizTalk2006.Application.ExportBindings BindingPath="bindingPath" Application="EAIApplication" GlobalParties="True" Server="server" Database="database" />]]>
    /// </code>
    /// <para>where:</para>
    /// <para><i>bindingPath (Required)</i></para>
    /// <para>
    /// The path to the XML file that the bindings will be exported into.
    /// </para>
    /// <para><i>Application</i></para>
    /// <para>
    /// The BizTalk application from which the Binding file should be exported.
    /// </para>
    /// <para><i>GroupLevel</i></para>
    /// <para>
    /// Indicates toe Export the binding at GroupLevel instead of an appication.
    /// </para>
    /// <para><i>GlobalParties</i></para>
    /// <para>
    /// Indicates toe Export also the global parties
    /// </para>
    /// <para><i>server</i></para>
    /// <para>
    /// The logical name of the server hosting the BizTalk management database. If neither this nor the
    /// database name are specified then the installation will default to the local installation.
    /// </para>
    /// <para><i>database</i></para>
    /// <para>
    /// The name of the BizTalk management database. If neither this nor the server name are specified 
    /// then the installation will default to the local installation.
    /// </para>
    /// <para><i>username</i></para>
    /// <para>
    /// The username to use to connect to the database if using SQL Server security. The default is to
    /// connect using Windows Integrated security.
    /// </para>
    /// <para><i>password</i></para>
    /// <para>
    /// The password to use to connect to the database if using SQL Server security. The default is to
    /// connect using Windows Integrated security.
    /// </para>
    /// </remarks>
    /// <example>
    /// <code><![CDATA[
    /// <Project>
    ///     <Target Name="Test" >
    ///         <!-- Export bindings using the application name -->
    ///         <BizTalk2006.Application.ExportBindings 
    ///             Application="EAIApplication"
    ///             GlobalParties="True"
    ///             Server="." 
    ///             Database="BizTalkMgmtDb" />
    ///         <!-- Export bindings at GroupLevel -->
    ///         <BizTalk2006.Application.ExportBindings 
    ///             GroupLevel="True"
    ///             Server="." 
    ///             Database="BizTalkMgmtDb" />
    ///     </Target>
    /// </Project>
    /// ]]></code>    
    /// </example>
    public class ExportBindings : BizTalk2004.Assembly.ExportBindings
    {
        #region Member Variables

        private string application;
        private bool globalParties;
        private bool groupLevel;

        #endregion

        #region Properties

        /// <summary>
        /// Gets or sets the application.
        /// </summary>
        /// <value>The application.</value>
        public string Application
        {
            get { return this.application; }
            set { this.application = value; }
        }

        /// <summary>
        /// Gets or sets to export global parties
        /// </summary>
        /// <value>
        /// <b>true</b> to export the global parties, or <b>false</b> otherwise. The default is
        /// <b>false</b>.
        /// </value>
        public bool GlobalParties
        {
            get { return this.globalParties; }
            set { this.globalParties = value; }
        }

        /// <summary>
        /// Gets or sets to export group level
        /// </summary>
        /// <value>
        /// <b>true</b> to export from group level, or <b>false</b> otherwise. The default is
        /// <b>false</b>.
        /// </value>
        public bool GroupLevel
        {
            get { return this.groupLevel; }
            set { this.groupLevel = value; }
        }

        #endregion

        /// <summary>
        /// Executes the task.
        /// </summary>
        protected override void InternalExecute()
        {
            if (string.IsNullOrEmpty(this.Application) && this.GroupLevel == false)
            {
                base.InternalExecute();
            }
            else
            {
                using (BtsCatalogExplorer explorer = this.GetBtsCatalogExplorer(this.Server, this.Database))
                {
                    using (SqlConnection sqlConnection = new SqlConnection(explorer.ConnectionString))
                    {
                        // Create Binding Info
                        BindingInfo bindingInfo = new BindingInfo();
                        BindingParameters bindingParameters = new BindingParameters(new Version(bindingInfo.Version));
                        bindingParameters.BindingItems = BindingParameters.BindingItemTypes.All;

                        // Check for the different settings
                        if (this.GroupLevel)
                        {
                            // Set bindingparameter to GroupLevel
                            bindingParameters.BindingScope = BindingParameters.BindingScopeType.Group;

                            Log.LogMessage(string.Format(CultureInfo.InvariantCulture, "Exporting Binding file for the Group {0}", explorer.GroupName));
                        }
                        else if (!string.IsNullOrEmpty(this.AssemblyPath) ||
                            (!string.IsNullOrEmpty(this.SimpleName) &&
                            !string.IsNullOrEmpty(this.PublicKeyToken) &&
                            !string.IsNullOrEmpty(this.Version)))
                        {
                            bindingParameters.BindingScope = BindingParameters.BindingScopeType.None;
                            AssemblyName assemblyName;

                            // Check if the Assembly can be written from Assembly or Create the correct name
                            if (!string.IsNullOrEmpty(this.AssemblyPath))
                            {
                                assemblyName = AssemblyName.GetAssemblyName(this.AssemblyPath);

                                // Get the correct culture as a string
                                string cultureInfo = assemblyName.CultureInfo != null ? "neutral" : assemblyName.CultureInfo.Name;

                                string publicKeyToken = null;

                                if (assemblyName.GetPublicKeyToken() != null)
                                {
                                    StringBuilder builder = new StringBuilder();

                                    foreach (byte token in assemblyName.GetPublicKeyToken())
                                    {
                                        builder.Append(token.ToString("x2", CultureInfo.InvariantCulture));
                                    }

                                    publicKeyToken = builder.ToString();
                                }

                                // Add the assembly name to the bindinginfo
                                Log.LogMessage(string.Format(CultureInfo.InvariantCulture, "Setup export for assembly {0}", assemblyName.FullName));
                                bindingInfo.AddModuleRef(assemblyName.Name, assemblyName.Version.ToString(), cultureInfo, publicKeyToken);
                            }
                            else
                            {
                                // Add the assembly name to the bindinginfo
                                Log.LogMessage(string.Format(CultureInfo.InvariantCulture, "Setup export for assembly {0}{1}{2}{3}", this.SimpleName, this.Version, this.Culture, this.PublicKeyToken));
                                bindingInfo.AddModuleRef(this.SimpleName, this.Version, this.Culture, this.PublicKeyToken);
                            }
                        }
                        else if (!string.IsNullOrEmpty(this.Application))
                        {
                            bindingParameters.BindingScope = BindingParameters.BindingScopeType.Application;

                            Log.LogMessage(string.Format(CultureInfo.InvariantCulture, "Setup export for application {0}", this.Application));
                            bindingInfo.AddApplicationRef(sqlConnection, this.Application);
                        }

                        // Only Set GlobalParty group when GroupLevel isn't set.
                        if (!this.GroupLevel)
                        {
                            Log.LogMessage(string.Format(CultureInfo.InvariantCulture, "Setup export will use globalparties: {0}", this.GlobalParties));
                            
                            // Set the GlobalParties
                            bindingParameters.IncludeGlobalParty = this.GlobalParties;
                        }

                        // Get all info from database
                        bindingInfo.Select(sqlConnection, bindingParameters);

                        // Check if the Path of the Destination really exists, or else create it
                        if (!Directory.Exists(Path.GetDirectoryName(this.BindingPath)))
                        {
                            Log.LogMessage(string.Format(CultureInfo.InvariantCulture, "Create destination directory: {0}", Path.GetDirectoryName(this.BindingPath)));
                            Directory.CreateDirectory(Path.GetDirectoryName(this.BindingPath));
                        }

                        // Check if the file has an extension? If not add the .xml extension.
                        if (!Path.HasExtension(this.BindingPath))
                        {
                            this.BindingPath = Path.ChangeExtension(this.BindingPath, ".xml");
                        }

                        // Write Bindinginfo to File
                        bindingInfo.SaveXml(this.BindingPath);
                        Log.LogMessage(string.Format(CultureInfo.InvariantCulture, "Bindingfile written to file: {0}", this.BindingPath));
                    }
                }
            }
        }
    }
}

